package com.davfx.httpnio;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.LinkedList;

import com.davfx.util.Log;

public final class UnthreadedWorker implements Worker, Runnable {
	private final Selector selector;
	private LinkedList<SelectorVisitor> queue = new LinkedList<SelectorVisitor>();
	private final Runnable heartbeatHandler;
	private final long heartbeatStep;
	private long nextHeartbeat = -1;

	public UnthreadedWorker() throws IOException {
		this(0, null);
	}
	
	public UnthreadedWorker(final long heartbeatStep, Runnable heartbeatHandler) throws IOException {
		selector = SelectorProvider.provider().openSelector();
		this.heartbeatStep = heartbeatStep;
		this.heartbeatHandler = heartbeatHandler;
		if (heartbeatHandler != null) {
			Thread d = new Thread(new Runnable() {
				@Override
				public void run() {
					while (true) {
						selector.wakeup();
						try {
							Thread.sleep(heartbeatStep);
						} catch (InterruptedException e) {
						}
					}
				}
			});
			d.start();
		}
	}
	
	public void add(SelectorVisitor visitor) {
		queue.addLast(visitor);
//		selector.wakeup();
	}
	
	public void run() {
		try {
			while (true) {
				if (heartbeatHandler != null) {
					long t = System.currentTimeMillis();
					if ((nextHeartbeat < 0) || (t >= nextHeartbeat)) {
						heartbeatHandler.run();
						nextHeartbeat = t + heartbeatStep;
					}
				}
				if (!queue.isEmpty()) {
					LinkedList<SelectorVisitor> q = queue;
					queue = new LinkedList<SelectorVisitor>();
					for (SelectorVisitor v : q) {
						v.visit(selector);
					}
				}
				if (queue.isEmpty()) {
					selector.select();
				}
				Iterator<SelectionKey> i = selector.selectedKeys().iterator();
				while (i.hasNext()) {
					SelectionKey key = i.next();
					i.remove();
					((SelectionKeyVisitor) key.attachment()).visit(key);
				}
			}
		} catch (IOException e) {
			Log.error("Server error", e);
		}
	}
}
